﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Neoit.Utils
{
    /// <summary>
    /// 常用加密算法，具有通用性
    /// </summary>
    public static class CryptoHelper
    {
        #region AES-对称加密
        /* 高级加密标准,替代原先的DES
         * 1,加密模式CipherMode：CBC（默认）、ECB（不推荐）、CTR、CFB、OFB
         * 2,填充模式PaddingMode：None，PKCS7，Zeros，ANSIX923，ISO10126
         * 3,密钥及KeySize: key（默认256） 若要显式设置keysize，则应先设置size，再设置key，即：aesAlg.KeySize = keySize; aesAlg.Key = Key;
         * 4,偏移量: iv
         * https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.aes?view=net-5.0
         */

        /// <summary>
        /// AES-加密
        /// 默认CipherMode.CBC、PaddingMode.PKCS7、KeySize=256、BlockSize=128、iv=key.Substring(0,16)
        /// 输出base64字符串
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string AES_Encrypt(string source, string key)
        {
            if (key == null || key.Length < 32) throw new ArgumentException("key值最少为32位");
            var keyByte = Encoding.UTF8.GetBytes(key);
            var IvByte = Encoding.UTF8.GetBytes(key[..16]);
            byte[] encrypted = AES_EncryptBase(source, keyByte, IvByte);
            var result = Convert.ToBase64String(encrypted);
            return result;
        }
        /// <summary>
        /// AES-解密
        /// </summary>
        public static string AES_Decrypt(string source, string key)
        {
            var cipherText = Convert.FromBase64String(source);
            if (key == null || key.Length < 32) throw new ArgumentException("key值最少为32位");
            var keyByte = Encoding.UTF8.GetBytes(key);
            var IvByte = Encoding.UTF8.GetBytes(key[..16]);//偏移量,最小为16
            string roundtrip = AES_DecryptBase(cipherText, keyByte, IvByte);
            return roundtrip;
        }
        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <param name="Key"></param>
        /// <param name="IV"></param>
        /// <param name="cipherMode"></param>
        /// <param name="paddingMode"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static byte[] AES_EncryptBase(string plainText, byte[] Key, byte[] IV, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.PKCS7)
        {
            // 检查参数
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException(nameof(plainText));
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException(nameof(Key));
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException(nameof(IV));

            byte[] encrypted;

            // 使用Aes类创建加密器对象
            using (Aes aesAlg = Aes.Create())
            {
                //aesAlg.KeySize = keySize;
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                aesAlg.Mode = cipherMode;
                aesAlg.Padding = paddingMode;

                // 创建加密器对象用于执行流转换
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                // 使用MemoryStream保存加密数据
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            // 写入所有数据到流中
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            return encrypted;
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <param name="Key"></param>
        /// <param name="IV"></param>
        /// <param name="cipherMode"></param>
        /// <param name="paddingMode"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static string AES_DecryptBase(byte[] cipherText, byte[] Key, byte[] IV, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.PKCS7)
        {
            // 检查参数
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException(nameof(cipherText));
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException(nameof(Key));
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException(nameof(IV));

            string plaintext = null;

            // 使用Aes类创建解密器对象
            using (Aes aesAlg = Aes.Create())
            {
                //aesAlg.KeySize = keySize;
                aesAlg.Key = Key;
                aesAlg.IV = IV;
                aesAlg.Mode = cipherMode;
                aesAlg.Padding = paddingMode;

                // 创建解密器对象用于执行流转换
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                // 使用MemoryStream读取加密数据
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // 从流中读取解密后的数据
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }

        #endregion
    }

}
